<?php
namespace app\common\model\traits;

use think\exception\ValidateException;

trait Event
{
    /**
     * 写入是否自动进行验证
     * @var bool
     */
    protected $autoValidate = true;

    /**
     * 验证器类
     * @var null
     */
    protected $validator = null;


    // 入库之前的数据处理
    protected  function  beforeValidate()
    {
        foreach ($this->getData() as $field => $value) {
            $item = $this->fieldsRule[$field] ?? [];
            if (empty($item)) {
                continue;
            }

            if (isset($item['filter'])) {
                if (is_string($item['filter']) && is_callable($item['filter'])) { // 函数字符串
                    $value = $item['filter']($value);
                } elseif (is_string($item['filter']) && method_exists($this, $item['filter'])) { // 模型方法
                    $value = call_user_func_array([$this, $item['filter']], [$value, $this->getData()]);
                } elseif (is_callable($item['filter'])) { // 匿名函数
                    $value = $item['filter']($value, $this->getData());
                }
            }

            $type = $item['type'] ?? 'string';
            switch ($type) {
                case 'text':
                case 'string':
                    if (is_array($value)) {
                        $this[$field] = json_encode($value, JSON_UNESCAPED_UNICODE);
                    }
                    $this[$field] = strip_tags((string) $value);
                    break;
                case 'integer':
                case 'int' :
                    $this[$field] = intval($value);
                    break;
                case 'float':
                case 'double':
                    $this[$field] = floatval($value);
                    break;
                case 'time':
                    $this[$field] = strtotime($value);
                    break;
                case 'blob':
                    $this[$field] = gzcompress($value);
                    break;
                case 'blob.array':
                    $this[$field] = gzcompress(serialize($value));
                    break;
                case 'html': // 富文本
                    // ...
                    break;
                case 'array':
                    $this[$field] = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICOD) : $value;
                    break;
            }
            if (is_array($value)) {
                $this[$field] = json_encode($value, JSON_UNESCAPED_UNICOD);
            }
        }
    }

    // 查询后
    public function afterReadCall()
    {
    }

    // 新增前
    public function beforeInsertCall()
    {
    }

    // 新增后
    public function afterInsertCall()
    {
    }

    // 更新前
    public function beforeUpdateCall()
    {
    }

    // 更新后
    public function afterUpdateCall()
    {
    }

    // 写入前
    public function beforeWriteCall()
    {
    }

    // 写入后
    public function afterWriteCall()
    {
    }

    // 删除前
    public function beforeDeleteCall()
    {
    }

    // 删除后
    public function afterDeleteCall()
    {
    }

    // 恢复前
    public function beforeRestoreCall()
    {
    }

    // 恢复后
    public function afterRestoreCall()
    {
    }

    // 模型事件静态方法改造为 普通方法定义 以下代码不动
    public static function onAfterRead($object)
    {
        return call_user_func([$object, 'afterReadCall']);
    }

    public static function onBeforeInsert($object)
    {
        // 数据处理
        $object->beforeValidate();
        // 自动进行数据验证
        $result = true;
        // 关闭自动验证 ： protected $autoValidate = false;
        // 动态设置关闭自动验证: 实例->isValidate(false)
        if ($object->autoValidate && $validate = get_validate_name($object->validator)) {
            $validate = validate($validate);
            // 自动验证
            $result = $validate
                ->scene('add')
                ->batch(true)
                ->failException(false) // 不使用抛异常的方式
                ->check($object->getData());
            if ($result !== true) {
                $object->setError($validate->getError());
            }
            // $validate->getError(); 数组的形式返回错误信息
        }

        $callReturn  = call_user_func([$object, 'beforeInsertCall']);
        return $result && ($callReturn === false ? false : true);
    }

    public static function onAfterInsert($object)
    {


        return call_user_func([$object, 'afterInsertCall']);
    }

    public static function onBeforeUpdate($object)
    {
        // 数据处理
        $object->beforeValidate();
        // 自动进行数据验证
        $result = true;
        if ($object->autoValidate && $validate = get_validate_name($object->validator)) {
            $validate = validate($validate);
            $result = $validate
                ->scene('edit')
                ->batch(true)
                ->failException(false)
                ->check($object->getData());
            if ($result !== true) {
                $object->setError($validate->getError());
            }
        }
        $callReturn = call_user_func([$object, 'beforeUpdateCall']);
        return $result && ($callReturn === false ? false : true);
    }

    public static function onAfterUpdate($object)
    {
        return call_user_func([$object, 'afterUpdateCall']);
    }

    public static function onBeforeWrite($object)
    {
        return call_user_func([$object, 'beforeWriteCall']);
    }

    public static function onAfterWrite($object)
    {
        return call_user_func([$object, 'afterWriteCall']);
    }

    public static function onBeforeDelete($object)
    {
        return call_user_func([$object, 'beforeDeleteCall']);
    }

    public static function onAfterDelete($object)
    {
        return call_user_func([$object, 'afterDeleteCall']);
    }

    public static function onBeforeRestore($object)
    {
        return call_user_func([$object, 'beforeRestoreCall']);
    }

    public static function onAfterRestore($object)
    {
        return call_user_func([$object, 'afterRestoreCall']);
    }

    /**
     * 动态设定本次写入是否自动验证
     * @param bool $is
     * @return $this
     */
    public function isValidate(bool $is = true)
    {
        $this->autoValidate = $is;
        return $this;
    }
}